package edu.example.paperselection;

import java.util.*;
import java.util.stream.Collectors;

public class PaperList {
    private final String teacher;
    private final List<Paper> papers;
    private final PaperSelection selectionResult = new PaperSelection();
    private PaperSelectionStrategy selectionStrategy = new RandomSelectionStrategy();

    public PaperList(String teacher, List<Paper> papers) {
        this.teacher = teacher;
        this.papers = papers;
    }

    public void setSelectionStrategy(PaperSelectionStrategy strategy) {
        this.selectionStrategy = strategy;
    }

    public synchronized List<Paper> selectPaperByRandom(Student student) throws NoEnoughPapersException {
        if (student.hasSelectedPapers()) {
            throw new IllegalArgumentException("学生已选过论文");
        }

        List<Paper> availablePapers = getAvailablePapers(student.getPreferredType());
        if (availablePapers.size() < student.getPreferredQuantity()) {
            throw new NoEnoughPapersException(
                    String.format("学生 %s 希望选 %d 篇论文，但只有 %d 篇可选",
                            student.getName(), student.getPreferredQuantity(), availablePapers.size()));
        }

        List<Paper> selectedPapers = selectionStrategy.selectPapers(availablePapers, student.getPreferredQuantity());
        for (Paper paper : selectedPapers) {
            // 即使 PaperSelection 用了 ConcurrentHashMap，此处仍需保证批量添加的原子性
            if (!selectionResult.addSelection(student, paper)) {
                // 极端情况：论文已被其他线程选中，抛出异常重试（或处理）
                throw new NoEnoughPapersException("论文已被选中，选择失败");
            }
        }
        student.markAsSelected();
        return selectedPapers;
    }

    private List<Paper> getAvailablePapers(PaperType type) {
        return papers.stream()
                .filter(paper -> !selectionResult.isSelected(paper))
                .filter(paper -> type == PaperType.Any ||
                        (paper instanceof Thesis && type == PaperType.Thesis) ||
                        (paper instanceof JournalPaper && type == PaperType.JournalPaper) ||
                        (paper instanceof ConferencePaper && type == PaperType.ConferencePaper))
                .collect(Collectors.toList());
    }

    public PaperSelection getSelectionResult() {
        return selectionResult;
    }
}